package com.taobao.snowsnow.web;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.struts2.ServletActionContext;
import org.dom4j.DocumentException;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.taobao.api.ApiException;
import com.taobao.snowsnow.hibernate.pojo.Address;
import com.taobao.snowsnow.hibernate.pojo.Express;
import com.taobao.snowsnow.hibernate.pojo.ExpressRecord;
import com.taobao.snowsnow.hibernate.pojo.Orders;
import com.taobao.snowsnow.hibernate.pojo.PostFee;
import com.taobao.snowsnow.hibernate.pojo.ProductCollect;
import com.taobao.snowsnow.hibernate.pojo.ProductTradeRecord;
import com.taobao.snowsnow.hibernate.pojo.Trade;
import com.taobao.snowsnow.hibernate.pojo.TradeRecord;
import com.taobao.snowsnow.hibernate.service.ExpressRecordService;
import com.taobao.snowsnow.hibernate.service.ExpressService;
import com.taobao.snowsnow.hibernate.service.PostFeeService;
import com.taobao.snowsnow.hibernate.service.ProductCollectService;
import com.taobao.snowsnow.hibernate.service.ProductTradeRecordService;
import com.taobao.snowsnow.hibernate.service.TradeRecordService;
import com.taobao.snowsnow.hibernate.service.TradeService;
import com.taobao.snowsnow.taobao.Logistics;
import com.taobao.snowsnow.taobao.TradeSync;
import com.taobao.snowsnow.util.ReadIni;
import com.taobao.snowsnow.util.Util;

public class TaoBaoAssistAction extends ActionSupport {
	private static final long serialVersionUID = 5493037390958519953L;
	
	private Express express;
	private ExpressRecord expressRecord;
	private Trade trade;
	
	private TradeService tradeService;
	private ExpressService expressService;
	private PostFeeService postFeeService;
	private ExpressRecordService expressRecordService;
	private TradeRecordService tradeRecordService;
	private ProductTradeRecordService productRecordService;
	private ProductCollectService productCollectService;
	
	private long tid;
	
	private String expressCode;
	private String outSid;
	private float weight;
	private String freightCollect;
	private String monthlyBalance;
	private boolean send_type;
	private boolean resend;
	
	private InputStream inputStream;
	
	/**
	 * <p>淘宝发货
	 * 1. 调用淘宝API发货
	 * 2. 保存发货的快递单记录(计算邮费价格)
	 * 3. 保存订单交易记录
	 * 4. 保存发货的商品记录
	 * 5. 保存运单号
	 * 6. 更新订单状态
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public String sendGoods() throws UnsupportedEncodingException {
		
		JSONObject jobject = new JSONObject();
		List<String> data = new ArrayList<String>();
		
		trade = tradeService.findByTid(tid);
		express = expressService.findByName(expressCode).get(0);
		
		boolean is_success = false;
		
		// 如果不是补发,则调用淘宝发货
		if(!resend) {
			// 1. 调用淘宝API发货
			is_success = sendByAPI(trade, data, jobject);
		} else {
			is_success = true;
		}
		
		// 2. 保存发货的快递单记录
		// 淘宝成功发货才保存快递单记录
		if(is_success) {
			// 发货时保存快递单记录
			try {
				setExpressRecord(trade);
			} catch (Exception e) {
				data.add("保存快递单记录出错!" + e.getMessage());
			}
			
			//3. 保存订单交易记录
			TradeRecord tRecord = new TradeRecord(trade, express, trade.getTotalPrice(), new Timestamp(Util.getDateTime().getTime()));
			try {
				tradeRecordService.create(tRecord);
			} catch (Exception e) {
				e.printStackTrace();
				data.add("保存订单交易记录出错");
			}
			
			//4. 保存发货的商品记录
			saveProductTradeRecord(data);
			
			//5. 保存运单号
			saveAWB(data);
			
			//6. 修改订单状态
			try {
				trade.setStatus(TradeSync.TRADE_FINISHED);
				tradeService.saveOrUpdate(trade);
			} catch (Exception e) {
				data.add("更新订单状态时出错!");
			}
			
		}
		
		jobject.put("data", JSONArray.fromObject(data));
		inputStream = new ByteArrayInputStream(jobject.toString().getBytes("utf8"));
		
		return SUCCESS;
	}

	/**
	 * <p>保存商品交易记录
	 */
	private void saveProductTradeRecord(List<String> data) {
		ProductTradeRecord pRecord = null;
		boolean meger = true;
		
		try {
			for(Orders o : trade.getOrders()) {
				ProductCollect collect = o.getProduct().getProductCollect();
				pRecord = productRecordService.findBySellDateAndProductCollect(new Timestamp(Util.getDate().getTime()), collect);
				if(pRecord == null) {
					pRecord = new ProductTradeRecord();
					meger = false;
				}
				
				if(meger) {
					pRecord.setQuantity(pRecord.getQuantity() + o.getQuantity());
				} else {
					pRecord.setProductCollect(collect);
					pRecord.setQuantity(o.getQuantity());
					pRecord.setSellPrice(o.getPrice());
					pRecord.setSellDate(new Timestamp(Util.getDateTime().getTime()));
				}
				
				productRecordService.saveOrUpdate(pRecord);
			}
		} catch (Exception e) {
			e.printStackTrace();
			data.add("保存商品交易记录出错");
		}
	}

	public String aa() {
		return SUCCESS;
	}
	
	/**
	 * <p>获取订单简单信息
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public String getTradeSimpleInfo() throws UnsupportedEncodingException {
		trade = tradeService.findByTid(tid);
		
		try {
			JSONObject json = new JSONObject();
			json.put("buyyer", trade.getPeople().getTaobaoId());
			json.put("address", trade.getPeople().getContacts().get(0).getDescs());
			
			inputStream = new ByteArrayInputStream(json.toString().getBytes("utf8"));
		} catch (Exception e) {
			inputStream = new ByteArrayInputStream("获取订单简单信息时出错".getBytes("utf8"));
		}
		
		return SUCCESS;
	}
	
	/**
	 * <p>读取ini文件
	 * @return
	 * 			返回上次发货的运单号
	 */
	public String getOutSidFromIni() {
		
		String awb = null;
		String fileName = "awb.ini";
		
		try {
			ReadIni ini = new ReadIni(getAWBIniPath() + fileName);
			
			awb = ini.getProperty(expressCode.toLowerCase() + ".awb"	);
		} catch (IOException e) {
			inputStream = new ByteArrayInputStream(("读取配置文件出错!").getBytes());
		}
		
		if(awb != null)
			inputStream = new ByteArrayInputStream(awb.getBytes());
		else
			inputStream = new ByteArrayInputStream("".getBytes());
		
		return SUCCESS;
	}
	
	private void setExpressRecord(Trade trade) throws Exception {
		
		expressRecord = new ExpressRecord();
		// TODO 默认取第一个联系人的第一个地址, 如果一个买家有多个联系人或者多个地址时就会有问题
		Address address = trade.getPeople().getContacts().get(0).getAddresses().get(0);
		
		// TODO 这里还没有计算快递的费用(快递的费用 =  首重 + 续重 * N)
		expressRecord.setAwb(trimMiddleSpace(outSid.trim()));
		expressRecord.setWeight(weight);
		
		// 如果是月结,则计算邮费价格
		if(monthlyBalance != null) {
			expressRecord.setMonthlyBalance(true);
			setPostFee(address.getState().getName());
		}
		
		if(freightCollect != null)
			expressRecord.setFreightCollect(true);
		
		expressRecord.setTrade(trade);
		expressRecord.setExpress(express);
		expressRecord.setAddress(address);
		expressRecord.setDate(Util.getDateTime());
		
		expressRecordService.create(expressRecord);
	}

	/**
	 * <p>设置邮费价格 邮费价格 = 首重 + 续重 * N
	 * @param state
	 * @throws Exception
	 */
	private void setPostFee(String state) throws Exception {
		PostFee fee = postFeeService.findByStateAndExpress(express, state);
		
		if(fee == null)
			throw new Exception("按省份查找不到: " + state);
		float firstPrice = 0f;
		float secondWeight = 0f;
		float price = 0f;
		if(weight <= 0.5)
			firstPrice = fee.getFirst500g();
		else if(weight > 0.5) 
			firstPrice = fee.getFirst1kg();
		
		secondWeight = weight - 1;
		
		if(secondWeight < 0)
			secondWeight = 0;
		else
			secondWeight = getSeconWeight(secondWeight);
		
		price = firstPrice + secondWeight * fee.getSecond500g();
		expressRecord.setPostFee(price);
	}
	
	private boolean sendByAPI(Trade trade, List<String> data, JSONObject jobject) throws UnsupportedEncodingException {
		
		int sendCount = 0;
		
		try {
			for(long t : setMultiTid(trade)) {
				// TODO 如果一个订单里有多个子订单, 那么在发货时,父订单成功发货后, 子订单发货又失败, 那就会出现漏发货的问题
				String str = null;
				
				// 如果是在线下单
				if(send_type) {
					
					// 如果有多个单,那只有第一个单是在线下单,其他单是离线下单
					if(sendCount == 0) {
						str = Logistics.onlineSendGoods(t, trimMiddleSpace(outSid.trim()), express.getCodeName());
						send_type = false;
					} 
				} else {
					str = Logistics.offlineSendGoods(t, trimMiddleSpace(outSid.trim()), express.getCodeName());
				}
				
				if(str != null)
					throw new Exception(str);
				else sendCount++;
			}
		} catch (ApiException e) {
			jobject.put("context", "发货失败");
			data.add("调用淘宝API出错!");
			return false;
		} catch (DocumentException e) {
			jobject.put("context", "发货失败~");
			data.add("解析淘宝返回的XML出错!");
			return false;
		} catch (Exception e) {
			jobject.put("context", "发货失败");
			data.add(e.getMessage());
			return false;
		}
		
		jobject.put("context", "成功发货" + sendCount + "单");
		
		return true;
	}
	
	/**
	 * <p>保存快递运单号 
	 */
	private void saveAWB(List<String> data) {
		String fileName = "awb.ini";
		try {
			ReadIni ini = new ReadIni(getAWBIniPath() + fileName);
			
			ini.saveProperty(expressCode.toLowerCase() + ".awb", expressRecord.getAwb());
			
		} catch (Exception e) {
			data.add("保存快递运单号出错");
		}
	}
	
	/**
	 * <p>获取运单的配置文件的路径
	 * @return
	 * 			的配置文件的路径
	 */
	private String getAWBIniPath() {
		HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST);
		return request.getSession().getServletContext().getRealPath("/") + "WEB-INF\\";
	}
	
	/**
	 * <p>设置要发货的订单 发货的订单 = 父单号 + N个子单号
	 * @param trade
	 * 			交易单
	 * @return
	 * 			一共要发货的订单号
	 */
	private List<Long> setMultiTid(Trade trade) {
		List<Long> tids = new ArrayList<Long>();
		
		tids.add(trade.getTid());
		
		String str = trade.getTradeTids();
		
		if(str != null) {
			for(String tmp : str.split(";")) {
				tids.add(Long.valueOf(tmp));
			}
		}
		
		return tids;
	}
	
	/**
	 * <p>过滤字符串中间的空格
	 * @param str
	 * 			要过滤的字符串
	 * @return
	 * 			去掉空格的字符串
	 */
	private String trimMiddleSpace(String str) {
		String filter_result = "";
		for(String t : str.split(" ")) {
			filter_result += t;
		}
		return filter_result.trim();
	}
	
	/**
	 * <p>计算续重重量,续重重量不足0.5按0.5计算,如0.8g按1KG计算
	 * @param weight
	 * @return
	 */
	private int getSeconWeight(float weight) {
		double d = weight / 0.5;
		int i = (int) d;
		
		if(d - i != 0)
			return i + 1;
		else 
			return i;
	}
	
	public long getTid() {
		return tid;
	}
	
	public void setTid(long tid) {
		this.tid = tid;
	}

	public float getWeight() {
		return weight;
	}

	public void setWeight(float weight) {
		this.weight = weight;
	}

	public String getMonthlyBalance() {
		return monthlyBalance;
	}

	public void setMonthlyBalance(String monthlyBalance) {
		this.monthlyBalance = monthlyBalance;
	}

	public boolean isSend_type() {
		return send_type;
	}

	public void setSend_type(boolean send_type) {
		this.send_type = send_type;
	}

	public String getFreightCollect() {
		return freightCollect;
	}

	public void setFreightCollect(String freightCollect) {
		this.freightCollect = freightCollect;
	}

	public InputStream getInputStream() {
		return inputStream;
	}

	public void setInputStream(InputStream inputStream) {
		this.inputStream = inputStream;
	}

	public Express getExpress() {
		return express;
	}

	public void setExpress(Express express) {
		this.express = express;
	}

	public ExpressRecord getExpressRecord() {
		return expressRecord;
	}

	public void setExpressRecord(ExpressRecord expressRecord) {
		this.expressRecord = expressRecord;
	}

	public Trade getTrade() {
		return trade;
	}

	public void setTrade(Trade trade) {
		this.trade = trade;
	}

	public String getExpressCode() {
		return expressCode;
	}

	public void setExpressCode(String expressCode) {
		this.expressCode = expressCode;
	}

	public String getOutSid() {
		return outSid;
	}

	public void setOutSid(String outSid) {
		this.outSid = outSid;
	}
	

	public boolean isResend() {
		return resend;
	}

	public void setResend(boolean resend) {
		this.resend = resend;
	}

	public TradeService getTradeService() {
		return tradeService;
	}

	public void setTradeService(TradeService tradeService) {
		this.tradeService = tradeService;
	}

	public ExpressService getExpressService() {
		return expressService;
	}

	public void setExpressService(ExpressService expressService) {
		this.expressService = expressService;
	}

	public ExpressRecordService getExpressRecordService() {
		return expressRecordService;
	}

	public void setExpressRecordService(ExpressRecordService expressRecordService) {
		this.expressRecordService = expressRecordService;
	}

	public TradeRecordService getTradeRecordService() {
		return tradeRecordService;
	}

	public void setTradeRecordService(TradeRecordService tradeRecordService) {
		this.tradeRecordService = tradeRecordService;
	}

	public ProductTradeRecordService getProductRecordService() {
		return productRecordService;
	}

	public void setProductRecordService(
			ProductTradeRecordService productRecordService) {
		this.productRecordService = productRecordService;
	}

	public ProductCollectService getProductCollectService() {
		return productCollectService;
	}

	public void setProductCollectService(ProductCollectService productCollectService) {
		this.productCollectService = productCollectService;
	}

	public PostFeeService getPostFeeService() {
		return postFeeService;
	}

	public void setPostFeeService(PostFeeService postFeeService) {
		this.postFeeService = postFeeService;
	}
}
